package com.ptkc.data.repository;

import com.ptkc.utils.MyUtil;
import com.ptkc.utils.NumberUtils;
import org.apache.lucene.search.join.ScoreMode;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.InnerHitBuilder;
import org.elasticsearch.index.query.NestedQueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.rest.RestStatus;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.SearchHits;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.elasticsearch.search.sort.SortOrder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.io.IOException;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.*;

/**
 * @author: Mr.Jiao
 * @date: 2018年12月28日
 */
@Component
public class DeliverCostRepository {

    @Autowired
    private RestHighLevelClient restHighLevelClient;


    public Map<String, Map<String,Double>> getDeliverCost(Collection<Integer> agents) throws IOException {
//        Map<String, Map<String,Double>> resultMap = new HashMap<>();
//        if(agents != null && agents.size() > 0){
//            for(Integer agentId : agents){
//                Map<String,Double> delivercost = this.getDeliverCost(agentId);
//                if(delivercost != null){
//                    resultMap.put(agentId.toString(), delivercost);
//                }
//            }
//        }else{
//            return this.getDeliverCost1(null);
//        }
//        return resultMap;
        return this.getDeliverCost1(agents);
    }

    public Map<String,Double> getDeliverCost(Integer agentId) throws IOException {
        SearchRequest request = new SearchRequest();
        SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
        NestedQueryBuilder nestedQueryBuilder = QueryBuilders.nestedQuery("timeslots", QueryBuilders.boolQuery(), ScoreMode.None);
        nestedQueryBuilder.innerHit(new InnerHitBuilder().setFrom(0).setSize(1000));
        sourceBuilder.query(QueryBuilders.boolQuery().must(QueryBuilders.termQuery("agentId", agentId)).must(nestedQueryBuilder));
        sourceBuilder.sort("isdefault", SortOrder.DESC);
        sourceBuilder.size(2).fetchSource(new String[]{"noCharge", "isdefault"}, null);
        request.source(sourceBuilder).indices("runfast_deliver_cost").types("delivercost");
        SearchResponse response = this.restHighLevelClient.search(request);
        Map<String,Double> deliverCost = null;
        if (response != null && response.status() == RestStatus.OK) {
            SearchHits searchHits = response.getHits();
            if(searchHits != null) {
                SearchHit[] hits = searchHits.getHits();
                if(hits != null){
                    Date nowTime = MyUtil.set(MyUtil.set(System.currentTimeMillis(), 1970, 0, 1),0,Calendar.MILLISECOND);
                    SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.sss'Z'");
                    sdf.setTimeZone(TimeZone.getTimeZone("UTC"));
                    for (SearchHit hit : hits){
                        Map<String, Object> searchItem = hit.getSourceAsMap();
                        if(searchItem == null){
                            continue;
                        }
                        Object noChargeObj = searchItem.get("noCharge");
                        if(noChargeObj == null || !NumberUtils.isRealNumber(noChargeObj.toString())){
                            continue;
                        }
                        Map<String, SearchHits> innerHit = hit.getInnerHits();
                        if(innerHit == null || innerHit.isEmpty()){
                            continue;
                        }
                        Double charge = null;
                        Double timeCost = null;
                        SearchHits searchHits1 = innerHit.get("timeslots");
                        if(searchHits1 != null && searchHits1.getHits() != null) {
                            SearchHit[] hits1 = searchHits1.getHits();
                            for(SearchHit hit1 : hits1){
                                Map<String, Object> objMap = hit1.getSourceAsMap();
                                if(objMap == null){
                                    continue;
                                }
                                Object startTimeObj = objMap.get("startTime");
                                Object endTimeObj = objMap.get("endTime");
                                if(startTimeObj == null || endTimeObj == null){
                                    continue;
                                }
                                Date startTime = null;
                                Date endTime = null;
                                try {
                                    startTime = sdf.parse(startTimeObj.toString());
                                    endTime = sdf.parse(endTimeObj.toString());
                                } catch (ParseException e) {
                                    e.printStackTrace();
                                    continue;
                                }

                                if(!nowTime.after(startTime) || !nowTime.before(endTime)){
                                    continue;
                                }

                                Object chargeObj = objMap.get("charge");
                                if(chargeObj  == null || !NumberUtils.isRealNumber(chargeObj.toString())){
                                    continue;
                                }
                                charge = Double.valueOf(chargeObj.toString());
                                Object costObj = objMap.get("timeCost");
                                if(costObj  == null || !NumberUtils.isRealNumber(costObj.toString())){
                                    continue;
                                }
                                timeCost = Double.valueOf(costObj.toString());
                                break;
                            }
                        }
                        Boolean isdefault = null;
                        Object isDefaultObj = searchItem.get("isdefault");
                        if(isDefaultObj == null || !"1".equals(isDefaultObj.toString())){
                            isdefault = false;
                        }else{
                            isdefault = true;
                        }
                        if(timeCost == null || charge == null){
                            if(isdefault){
                                break;
                            }else {
                                continue;
                            }
                        }
                        if(deliverCost == null || isdefault) {
                            if(deliverCost == null){
                                deliverCost = new HashMap<>();
                            }
                            deliverCost.put("noCharge", Double.valueOf(noChargeObj.toString()));
                            deliverCost.put("charge", charge);
                            deliverCost.put("timeCost", timeCost);
                        }
                        if(isdefault){
                            break;
                        }
                    }
                }
            }
        }
        return deliverCost;
    }

    public Map<String, Map<String,Double>> getDeliverCost1(Collection<Integer> agents) throws IOException {
        SearchRequest request = new SearchRequest();
        SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
        BoolQueryBuilder parentQueryBuilder = QueryBuilders.boolQuery();
        if(agents != null && agents.size() > 0) {
            parentQueryBuilder.must(QueryBuilders.termsQuery("agentId", agents));
        }
        Date nowTime = MyUtil.set(MyUtil.set(System.currentTimeMillis(), 1970, 0, 1),0,Calendar.MILLISECOND);
        BoolQueryBuilder nestedQuery = QueryBuilders.boolQuery().must(QueryBuilders.rangeQuery("timeslots.startTime").lte(nowTime)).must(QueryBuilders.rangeQuery("timeslots.endTime").gte(nowTime));
        NestedQueryBuilder nestedQueryBuilder = QueryBuilders.nestedQuery("timeslots", nestedQuery, ScoreMode.None);
        nestedQueryBuilder.innerHit(new InnerHitBuilder().setFrom(0).setSize(1000));
        parentQueryBuilder.must(nestedQueryBuilder);
        sourceBuilder.query(parentQueryBuilder).from(0).size(10000).fetchSource(new String[]{"noCharge", "agentId", "isdefault"}, null);
        request.source(sourceBuilder).indices("runfast_deliver_cost").types("delivercost");
        SearchResponse response = this.restHighLevelClient.search(request);
        Map<String, Map<String,Double>> delivercostMap = new HashMap<>();
        if(response.status() == RestStatus.OK){
            SearchHits searchHits = response.getHits();
            if(searchHits != null) {
                SearchHit[] hits = searchHits.getHits();
                if(hits != null) {
                    for (SearchHit hit : hits){
                        if(hit != null){
                            Map<String, Object> searchItem = hit.getSourceAsMap();
                            Object agentIdObj = searchItem.get("agentId");
                            if(agentIdObj == null || !NumberUtils.isPositiveInteger(agentIdObj.toString())){
                                continue;
                            }
                            Boolean isDefault = null;
                            Object isDefaultObj = searchItem.get("isdefault");
                            if(isDefaultObj != null && !"1".equals(isDefaultObj.toString())){
                                isDefault = true;
                            }
                            if(isDefault == null){
                                isDefault = false;
                            }
                            Object noChargeObj = searchItem.get("noCharge");
                            if(noChargeObj == null || !NumberUtils.isRealNumber(noChargeObj.toString())){
                                continue;
                            }
                            Double charge = null;
                            Double timeCost = null;
                            Map<String, SearchHits> innerHit = hit.getInnerHits();
                            if(innerHit == null || innerHit.isEmpty()){
                                continue;
                            }
                            SearchHits searchHits1 = innerHit.get("timeslots");
                            if(searchHits1 != null && searchHits1.getHits() != null) {
                                SearchHit[] hits1 = searchHits1.getHits();
                                for(SearchHit hit1 : hits1){
                                    Map<String, Object> objMap = hit1.getSourceAsMap();
                                    if(objMap == null){
                                        continue;
                                    }
                                    Object chargeObj = objMap.get("charge");
                                    if(chargeObj  == null || !NumberUtils.isRealNumber(chargeObj.toString())){
                                        continue;
                                    }
                                    charge = Double.valueOf(chargeObj.toString());
                                    Object costObj = objMap.get("timeCost");
                                    if(costObj  == null || !NumberUtils.isRealNumber(costObj.toString())){
                                        continue;
                                    }
                                    timeCost = Double.valueOf(costObj.toString());
                                    break;
                                }
                            }
                            if(timeCost == null || charge == null){
                                continue;
                            }
                            Map<String, Double> deliverCost = new HashMap<>();
                            deliverCost.put("noCharge", Double.valueOf(noChargeObj.toString()));
                            deliverCost.put("charge", charge);
                            deliverCost.put("timeCost", timeCost);
                            String agentStr = agentIdObj.toString();
                            if(delivercostMap.containsKey(agentStr)) {
                                if(isDefault){
                                    delivercostMap.put(agentStr, deliverCost);
                                }
                            }else{
                                delivercostMap.put(agentStr, deliverCost);
                            }
                        }
                    }
                }
            }
        }
        return delivercostMap;
    }

}
